import {FreshImmortal, ImmortalDetail} from "db://assets/proto/shared/v1/wuni";
import {http} from "db://assets/script/common/HTTP";
import {
    FishAliveRequest,
    FishAliveResult,
    FishMoveRequest,
    FishMoveResult,
    FishSleepRequest,
    FishSleepResult
} from "db://assets/proto/new-world-api/v1/fish";
import {userInfo} from "db://assets/script/user-info";
import {FishStatus} from "db://assets/proto/shared/v1/biz";
import {FishAliveEvent} from "db://assets/script/common/events/fish-events/fish-alive-event";
import {FishSleepEvent} from "db://assets/script/common/events/fish-events/fish-sleep-event";
import {director} from "cc";
import {GameEvent} from "db://assets/script/game-event";
import {lobby} from "db://assets/script/lobby";
import {FishMoveEvent} from "db://assets/script/common/events/fish-events/fish-move-event";
import {FishBeginMoveEvent} from "db://assets/script/common/events/fish-events/fish-begin-move-event";
import {serverTimeHelper} from "db://assets/script/server-time-helper";
import Long from "long";
import {FishExploreReply, FishMoveCompleteReply} from "db://assets/proto/new-world-ws/v1/internal";
import {FishCoreChangeEvent} from "db://assets/script/common/events/fish-events/fish-core-change-event";
import {cmm} from "db://assets/script/utils/cmm";

export class Fish {
    freshFish!: FreshImmortal
    parking!: string
    bagCount!: number

    constructor(fd: ImmortalDetail) {
        this.bagCount = fd.bagPropCount.toNumber()
        this.parking = fd.parking
        this.freshFish = fd.fish!
        this.onActionEvent()
        this.onNotifyEvent()
        if (fd.fish!.status == FishStatus.alive) {
            console.log("Fish status: " + fd.fish!.status)
            console.log("Fish complete at ms: " + fd.fish!.goHomeAtMs.toNumber())
            console.log("server time: " + serverTimeHelper.loadServerTime())
            const goHomeMs = fd.fish!.goHomeAtMs.toNumber() - serverTimeHelper.loadServerTime()
            setTimeout(() => {
                if (fd.fish!.status == FishStatus.alive) director.emit(GameEvent.fishCoreChange, new FishCoreChangeEvent(fd.fish!.id, (ff) => {
                    ff.status = FishStatus.sleep
                }))
            }, goHomeMs)
        }
    }

    onNotifyEvent() {
        director.on(GameEvent.fishMoveComplete, this._onNotifyMoveComplete, this)
        director.on(GameEvent.fishBeginExplore, this._onNotifyExplore, this)
    }

    offNotifyEvent() {
        director.off(GameEvent.fishMoveComplete, this._onNotifyMoveComplete, this)
        director.off(GameEvent.fishBeginExplore, this._onNotifyExplore, this)
    }

    onActionEvent() {
        director.on(GameEvent.fishActionActive, this._actionActive, this)
        director.on(GameEvent.fishActionSleep, this._actionSleep, this)
        director.on(GameEvent.fishActionMove, this._actionMove, this)
    }

    offActionEvent() {
        director.off(GameEvent.fishActionActive, this._actionActive, this)
        director.off(GameEvent.fishActionSleep, this._actionSleep, this)
        director.off(GameEvent.fishActionMove, this._actionMove, this)
    }

    async _actionActive(event: FishAliveEvent) {
        if (event.fishId != this.freshFish.id) return
        const param = FishAliveRequest.create({
            fishId: event.fishId,
            zoneId: event.zoneId,
            aliveDuration: event.aliveDuration,
        })
        return http.requestAsync("POST", "v1/fish/alive", FishAliveResult, FishAliveRequest.encode(param).finish())
            .then(_ => {
                const fish = userInfo.loadFishById(event.fishId)!
                fish!.status = FishStatus.alive;
                fish!.goHomeAtMs = event.aliveDuration.add(serverTimeHelper.loadServerTime())
                director.emit(GameEvent.uiUpdateFish, event.fishId)
                director.emit(GameEvent.changeBattleRole, event.fishId)
                director.emit(GameEvent.uiChangeAliveDuration, fish.goHomeAtMs)
                director.emit(GameEvent.uiChangeZoneName, fish.zoneId)
                lobby.instance.clearAllTempUI()
            })
            .catch(() => lobby.instance.showToast("探索失败"))
    }

    async _actionSleep(event: FishSleepEvent) {
        console.log('try sleep', event.fishId)
        if (event.fishId != this.freshFish.id) return
        const param = FishSleepRequest.create({
            fishId: event.fishId,
            zoneId: event.zoneId
        })
        return http.requestAsync("POST", "v1/fish/sleep", FishSleepResult, FishSleepRequest.encode(param).finish())
            .then(_ => {
                const fish = userInfo.loadFishById(event.fishId)!
                fish!.status = FishStatus.sleep
                director.emit(GameEvent.uiUpdateFish, event.fishId)
                if (userInfo.fishInfo.currentShowFishInBattle?.eq(event.fishId)) director.emit(GameEvent.uiChangeAliveDuration, Long.fromNumber(-1))
                lobby.instance.clearAllTempUI()
            })
            .catch(() => lobby.instance.showToast("回家失败"))
    }

    async _actionMove(event: FishMoveEvent) {
        console.log('try move', event.fishId)
        if (event.fishId != this.freshFish.id) return
        const param = FishMoveRequest.create({
            fishId: this.freshFish.id,
            from: this.freshFish.zoneId,
            to: event.targetZoneId
        })
        return http.requestAsync("POST", "v1/fish/move", FishMoveResult, FishMoveRequest.encode(param).finish())
            .then(resp => {
                const fish = userInfo.loadFishById(event.fishId)!
                fish!.status = FishStatus.moving
                fish!.completeAtMs = resp.completeAtMs
                director.emit(GameEvent.uiUpdateFish, event.fishId)
                director.emit(GameEvent.fishBeginMove, new FishBeginMoveEvent(event.fishId, resp.completeAtMs))
            })
            .catch(() => lobby.instance.showToast("移动失败"))
    }


    private _onNotifyMoveComplete(event: FishMoveCompleteReply) {
        if (this.freshFish.id?.eq(event.fishId)) {
            director.emit(GameEvent.fishCoreChange, new FishCoreChangeEvent(event.fishId, (ff) => {
                ff.completeAtMs = Long.fromNumber(-1)
                ff.status = FishStatus.alive
                ff.zoneId = event.zoneId
            }))
        }
    }

    private _onNotifyExplore(event: FishExploreReply) {
        let propWeight = 0
        this.freshFish.assetInfo!.props.forEach((_, num) => propWeight + num.toNumber())
        director.emit(GameEvent.fishCoreChange, new FishCoreChangeEvent(event.fishId, (ff) => {
            ff.battleInfo!.currentMagicPower = event.currentMagicPower
            ff.battleInfo!.finalBattleInfo!.magicPower = event.magicPower
            ff.battleInfo!.finalBattleInfo!.magicPowerBonus = event.magicPowerBonus
            if (propWeight < 500) {
                ff.assetInfo!.props = cmm.longMapMerge(ff.assetInfo!.props, event.prop!, (v1, v2) => v1.add(v2))
                director.emit(GameEvent.uiUpdateFishBag, event.fishId)
            }
        }))
    }

}